﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Runtime.Serialization;
using System.Windows.Input;
using RG.Common.Configuration;
using RG.Common.WPF.Commands;
using RG.Common.WPF.Dialogs;
using RG.Common.WPF.Filters;
using Microsoft.Practices.Unity;
using RG.Common.WPF;

namespace RG.Common.WPF.BaseFrame
{
    [SupportDataBinding]
    [DataContract]
    public class FilterSettings : INotifyPropertyChanged,IFirePropertyChanged
    {
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public int Position { get; set; }

        [DataMember]
        public string Name { get; set; }

        private FilterVisibleMode mode { get; set; }


        [DataMember]
        public FilterVisibleMode Mode
        {
            get { return mode; }
            set { mode = value; }
        }

        /// <summary>
        /// Использовать для установки режима из фрейма
        /// </summary>
        [DataMember]
        public FilterVisibleMode ModeFromFrame
        {
            get { return mode; }
            set
            {
                mode = value;
                ValueFromParent = true;
            }
        }


        public bool ValueFromParent { get; set; }

        [DependOn("Mode")]
        public bool ComboVisible
        { get { return Mode != FilterVisibleMode.Недоступен; } }

        [DependOn("Mode")]
        public bool TextVisible
        { get { return Mode == FilterVisibleMode.Недоступен; } }

        public List<FilterVisibleMode> Modes
        {
            get
            {
                return Enum.GetValues(typeof (FilterVisibleMode)).ToList<FilterVisibleMode>()
                    .Where(x=>x!= FilterVisibleMode.Недоступен).ToList();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public void Unsubscribe()
        {
            PropertyChanged = null;
        }
    }
    
    [SupportDataBinding]
    public class FiltersVM 
    {
        [Dependency]
        public IUnityContainer Cfg { get; set; }

        [Dependency]
        public WorkplaceWorker Worker { get; set; }

        private List<FilterSettings> settings;

        public string FiltersName { get; set; }


        public bool HideExpander { get; set; }

        [PropertySetting(DefaultValue = true)]
        public bool IsExpanded { get; set; }

        private ObservableCollection<FilterBaseVM> filter;
        public  ObservableCollection<FilterBaseVM> Filter
        {
            get { return filter; }
            set { filter = value; }
        }

        public FilterBaseVM SelectedItem { get; set; }

        public ICommand ClearFiltersCmd { get; set; }

        public ICommand SettingsCmd { get; set; }
        public ICommand CollapseAllCmd { get; set; }
        public ICommand UncollapseAllCmd { get; set; }
        public ICommand ShowAllCmd { get; set; }


        [PropertySetting(SaveNullValue = true,SerializeAs = SettingsSerializeAs.Xml)]
        public List<FilterSettings> Settings
        {
            get { return settings; }
            set
            {
                SetSettings(value);
            }
        }

        private void SetSettings(List<FilterSettings> value)
        {
            if (Filter != null && Filter.Any() && Settings!=null && Settings.Any())
            {
                foreach (var filterSettingse in value)
                {
                    var temp = settings.FirstOrDefault(x => x.Name == filterSettingse.Name);
                    if(temp!=null && !temp.ValueFromParent)
                    {
                        temp.Mode = filterSettingse.Mode;
                        temp.Position = filterSettingse.Position;
                    }

                }
                
                foreach (var filterSetting in Settings)
                {
                    //находим нужный фильтр
                    var temp = Filter.FirstOrDefault(x => x.Name == filterSetting.Name);
                    if (temp != null)
                    {
                        temp.Settings = filterSetting;
                    }
                }
                Filter = Filter.OrderBy(x => x.Settings.Position).ToObservableCollection();
            }

        }

        public FiltersVM()
        {
            Filter = new ObservableCollection<FilterBaseVM>();
            ClearFiltersCmd = new DelegateCommand(DoClearFilters);
            SettingsCmd = new DelegateCommand(DoSettings);
            CollapseAllCmd = new DelegateCommand(DoCollapseAll);
            UncollapseAllCmd = new DelegateCommand(DoUncollapseAll);
            ShowAllCmd = new DelegateCommand(DoShowAll);
            FiltersName = "Фильтры";
        }

        private void DoShowAll()
        {
            foreach (var filter in Filter)
            {
                if (filter.Settings.Mode == FilterVisibleMode.Невидим)
                {
                    filter.Settings.Mode = FilterVisibleMode.Авто;
                }
            }

        }

        private void DoUncollapseAll()
        {
            foreach (var filter in Filter)
            {
                if (filter.Settings.Mode == FilterVisibleMode.Авто)
                    filter.Settings.Mode = FilterVisibleMode.Развернут;
            }
        }

        private void DoCollapseAll()
        {
            foreach (var filter in Filter)
            {
                if (filter.Settings.Mode == FilterVisibleMode.Развернут)
                {
                    filter.Settings.Mode = FilterVisibleMode.Авто;
                }
                if (filter.IsSelected)
                    filter.IsSelected = false;
            }
        }

        private void DoSettings()
        {
            var vm = Cfg.Resolve<FilterSettingsDialogVM>();
            vm.Load(Settings);
            if (Worker.Workplace.ShowEditableDialog(vm, String.Format("Настройки фильтров")))
            {
                Settings = vm.Get();
            }
        }

        private void DoClearFilters()
        {
            foreach (var filterBaseVM in Filter)
            {
                filterBaseVM.ClearValueQuiet();
            }
        }

        public void InitFiltersSettings()
        {
            var newSettings = new List<FilterSettings>();
            if (Settings == null || !Settings.Any())
            {
                int i = 0;
                foreach (var filterBaseVM in Filter)
                {
                    var temp = new FilterSettings
                                   {
                                       Name = filterBaseVM.Name,
                                       Mode = FilterVisibleMode.Развернут,
                                       Position = i++
                                   };
                    filterBaseVM.Settings = temp;
                    newSettings.Add(temp);
                }
            }
            else //если есть, то будем обрабатывать
            {
                //выбираем фильтры, по которым есть настройки
                var filtersWithSettings = Filter.Where(x =>
                                                           {
                                                               var temp = Settings.Select(y => y.Name).ToList();
                                                               return temp.Contains(x.Name);
                                                           }).ToList();
                //находим старые настройки, которые надо убить
                var settingsToKill = Settings.Where(x => !Filter.Select(y => y.Name).ToList().Contains(x.Name)).ToList();
                //ищем фильтры, для которых надо замутить настройку
                var filtersWithoutSettings = Filter.Where(x => !Settings.Select(y => y.Name).ToList().Contains(x.Name)).ToList();

                //настройки только актуальные
                newSettings = Settings.Where(x => !settingsToKill.Contains(x)).ToList();

                //Добавляем настройки
                int i =newSettings.Any()? newSettings.Max(x => x.Position):-1;
                foreach (var filterBaseVM in filtersWithoutSettings)
                {
                    var temp = new FilterSettings()
                    {
                        Name = filterBaseVM.Name,
                        Mode = FilterVisibleMode.Развернут,
                        Position = ++i
                    };
                    filterBaseVM.Settings = temp;
                    newSettings.Add(temp);
                }

                //Обновляем старые настройки в фильтрах
                foreach (var filtersWithSetting in filtersWithSettings.Where(x=>!x.Settings.ValueFromParent))
                {
                    //находим нужный сеттинг
                    var temp = newSettings.FirstOrDefault(
                        x => x.Name == filtersWithSetting.Name);

                    filtersWithSetting.Settings = temp;
                }

            }
            settings = newSettings;
        }

        public void Load(IEnumerable<FilterBaseVM> source)
        {
            Filter = source.ToObservableCollection();
            InitFiltersSettings();
            //SettingsLoaded();
        }

     

        public TT Get<TT>(string id) where TT : FilterBaseVM
        {
            foreach (var item in Filter)
                if (item.Id == id)
                    return (TT)item;

            throw new ApplicationException(string.Format("Не нашли фильтр '{0}'", id));
        }

        public void ClearCurrentFilter()
        {
            if (SelectedItem != null)
                SelectedItem.ClearValueQuiet();
        }
    }
}
